package com.it.controller;

import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.search.Hit;
import co.elastic.clients.elasticsearch.core.search.HitsMetadata;
import co.elastic.clients.json.JsonData;
import com.it.config.ElasticSearchClientConnect;
import com.it.entity.Person;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ES文档操作
 */
@RestController
public class ElasticsearchDocumentController {

    @Autowired
    private ElasticSearchClientConnect elasticSearchClientConfig;

    /**
     * 添加document
     * @throws IOException
     */
    @GetMapping("/addDocument")
    public void addDocument() throws IOException {

        // 向Person对象中添加数据
        Person Person = new Person("java客户端", "男", 18);
        // 向索引中添加数据
        CreateResponse createResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().create(e -> e.index("my_index").id("1001").document(Person));
        System.out.println("createResponse.result() = " + createResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 查询document
     * @throws IOException
     */
    @GetMapping("/queryDocument")
    public void queryDocument() throws IOException {
        // 构建请求
        GetResponse<Person> getResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().get(e -> e.index("my_index").id("1001"), Person.class);
        System.out.println("getResponse.source().toString() = " + getResponse.source().toString());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 修改document
     * @throws IOException
     */
    @GetMapping("/modifyDocument")
    public void modifyDocument() throws IOException {

        // 使用map集合封装需要修改的内容
        Map<String, Object> map = new HashMap<>();
        map.put("name", "java客户端aaa");
        // 构建请求
        UpdateResponse<Person> updateResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().update(e -> e.index("my_index").id("1001").doc(map), Person.class);
        System.out.println("updateResponse.result() = " + updateResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 删除document
     * @throws IOException
     */
    @GetMapping("/removeDocument")
    public void removeDocument() throws  IOException {

        // 构建请求
        DeleteResponse deleteResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().delete(e -> e.index("my_index").id("1001"));
        System.out.println("deleteResponse.result() = " + deleteResponse.result());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 批量添加document
     * @throws IOException
     */
    @GetMapping("/batchAddDocument")
    public void batchAddDocument() throws IOException {

        // 构建一个批量数据集合
        List<BulkOperation> list = new ArrayList<>();
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test2", "男", 19)).id("1002").index("Person_test")).build());
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test3", "男", 20)).id("1003").index("Person_test")).build());
        list.add(new BulkOperation.Builder().create(
                d -> d.document(new Person("test4", "女", 21)).id("1004").index("Person_test")).build());
        // 调用bulk方法执行批量插入操作
        BulkResponse bulkResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().bulk(e -> e.index("Person_test").operations(list));
        System.out.println("bulkResponse.items() = " + bulkResponse.items());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 批量删除document
     * @throws IOException
     */
    @GetMapping("/batchDeleteDocument")
    public void batchDeleteDocument() throws IOException {

        // 构建一个批量数据集合
        List<BulkOperation> list = new ArrayList<>();
        list.add(new BulkOperation.Builder().delete(
                d -> d.id("1002").index("Person_test")).build());
        list.add(new BulkOperation.Builder().delete(
                d -> d.id("1003").index("Person_test")).build());
        // 调用bulk方法执行批量插入操作
        BulkResponse bulkResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().bulk(e -> e.index("Person_test").operations(list));
        System.out.println("bulkResponse.items() = " + bulkResponse.items());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 全量查询document
     * @throws IOException
     */
    @GetMapping("/queryAllDocument")
    public void queryAllDocument() throws IOException {

        // 全量查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(e -> e.index("Person_test").query(q -> q.matchAll(m -> m)), Person.class);
        HitsMetadata<Person> hits = searchResponse.hits();
        for (Hit<Person> hit : hits.hits()) {
            System.out.println("Person = " + hit.source().toString());
        }
        System.out.println("searchResponse.hits().total().value() = " + searchResponse.hits().total().value());

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 分页查询document
     * @throws IOException
     */
    @GetMapping("/pagingQueryDocument")
    public void pagingQueryDocument() throws IOException {

        // 分页查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test")
                        .query(q -> q.matchAll(m -> m))
                        .from(0)
                        .size(2)
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));
        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 排序查询document
     * @throws IOException
     */
    @GetMapping("/sortQueryDocument")
    public void sortQueryDocument() throws IOException {

        // 排序查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test")
                        .query(q -> q.matchAll(m -> m))
                        .sort(o -> o.field(f -> f.field("age").order(SortOrder.Asc)))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 条件查询document
     * @throws IOException
     */
    @GetMapping("/conditionQueryDocument")
    public void conditionQueryDocument() throws IOException {

        // 条件查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test").query(q -> q.matchAll(m -> m))
                        .sort(o -> o.field(f -> f.field("age").order(SortOrder.Asc)))
                        .source(r -> r.filter(f -> f.includes("name", "age").excludes("")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 组合查询  must是必须满足所有条件，should只要满足一个就行
     * @throws IOException
     */
    @GetMapping("/combinationQueryDocument")
    public void combinationQueryDocument() throws IOException {

        // 组合查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
                s -> s.index("Person_test").query(q -> q.bool(b -> b
                        .must(m -> m.match(u -> u.field("age").query(21)))
                        .must(m -> m.match(u -> u.field("sex").query("男")))
                        .mustNot(m -> m.match(u -> u.field("sex").query("女")))
                ))
                , Person.class);


        //SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(
        //                s -> s.index("Person_test").query(q -> q.bool(b -> b
        //                        .should(h -> h.match(u -> u.field("age").query(19)))
        //                        .should(h -> h.match(u -> u.field("sex").query("男")))
        //                ))
        //                , Person.class);

        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 范围查询
     * @throws IOException
     */
    @GetMapping("/scopeQueryDocument2")
    public void scopeQueryDocument2() throws IOException {

        // 范围查询，gte()表示取大于等于，gt()表示大于，lte()表示小于等于
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .range(r -> r.field("age").gte(JsonData.of(20)).lt(JsonData.of(21))))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }


    /**
     * 模糊查询
     * @throws IOException
     */
    @GetMapping("/fuzzyQueryDocument2")
    public void fuzzyQueryDocument2() throws IOException {

        // 模糊查询，fuzziness表示差几个可以查询出来
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .fuzzy(f -> f.field("name").value("tst").fuzziness("2")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 高亮查询
     * @throws IOException
     */
    @GetMapping("/highlightQueryDocument2")
    public void highlightQueryDocument2() throws IOException {

        // 高亮查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").query(q -> q
                        .term(t -> t.field("name").value("test4")))
                        .highlight(h -> h.fields("name", f -> f.preTags("<font color='red'>").postTags("</font>")))
                , Person.class);
        searchResponse.hits().hits().forEach(h -> System.out.println(h.source().toString()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }


    /**
     * 聚合查询
     * @throws IOException
     */
    @GetMapping("/aggregateQueryDocument2")
    public void aggregateQueryDocument2() throws IOException {

        // 聚合查询，取最大年龄
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test").aggregations("maxAge", a ->a.max(m -> m.field("age")))
                , Person.class);
        searchResponse.aggregations().entrySet().forEach(f -> System.out.println(f.getKey() + ":" + f.getValue().max().value()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }

    /**
     * 分组查询
     * @throws IOException
     */
    @GetMapping("/groupQueryDocument2")
    public void groupQueryDocument2() throws IOException {

        // 分组查询
        SearchResponse<Person> searchResponse = elasticSearchClientConfig.restClient().getElasticsearchClient().search(s -> s.index("Person_test")
                        .aggregations("ageGroup", a ->a.terms(t -> t.field("age")))
                , Person.class);
        searchResponse.aggregations().get("ageGroup").lterms().buckets().array().forEach(f -> System.out.println(f.key() + ":" + f.docCount()));

        elasticSearchClientConfig.restClient().getElasticsearchTransport().close();
        elasticSearchClientConfig.restClient().getRestClient().close();
    }
}
